Python 是一門相對比較好上手的程式語言,簡潔的表述與直覺的語句使許多人易於上手;筆者作為一個初學者,想在學習 python 的過程中留一些筆記,也希望可以幫助到其他正在學習的人。
筆記目錄:
-1. 基礎概念與語法速覽
-2. 未定
python 作為動態型語言,其變數的資料型態(data type)是在運行時(Rum-time)動態決定的,因此變數的宣告方式也相當直觀;而對於變數與變數之間的運算,運算結果的資料型態也是動態決定的,因此不用苦思儲存時的型別為何。然而動態語言的特性相對上也增加了程式設計師的責任,需要去注意這些隱性型態轉換的結果是否符合預期,雖然也有一些時候需要強制去轉換計算的結果型態,不過動態的宣告與轉換資料型態在大部分的情況還是相當友善的。
此外,變數的資料型態相當多樣,除了基礎的數字類型,例如:整數(interger)、浮點數(float)、複數(complex),布零值(bool)、字串(string)等也有提供;而構建於這些基本的型別上,你也可以自行定義類別(class)來取得對應的資料型別。定義完變數後,許多變數的內容可透過 print 函數來查看輸出的值,其中與 format 函數搭配使用可以格式化輸出的內容,並提升輸出窗口(Console)的可讀性。
eg.1-1
## I agree ';' is not a good idea in python..
int_var = 10 ; str_var = "Hello_var"
complx_var = 4+3j ; bool_var = true ;
# transfer into str type
str_result = int_var * str_var
print("int * str will get : {}".format(str_result))
## self-define -
## class cls_name(base_cls) : for inherent.
class my_class:
def __init__(self, x):
self.my_data = x
## \n for replace newline
print("declare your class object \n")
my_object = my_class(complx_var)
print("my_object copied the complx var : {}\n".format(
my_object))
容器(Container),以上述的內建型別為基礎,用於儲存、提取這些型別所創建的物件;而每種容器都提供了一種儲存資料的特殊方式,例如:串列(list)塑造一維的向量結構,字典(dict)塑造了鍵值對(key-value pair)的結構,元組(tuple)則塑造了一個不可變動的有序組(ordered),而 Python 內建的容器也相當豐富,包含以上的各個容器類型。
Python 內建各種類型的容器使我們在開發和一些特定場景的應用上能較好的實現相關功能,例如兩台電腦進行網路資料傳輸時,有時會運用 Dequeue 作為傳輸間的暫存區,以實現具優先權的資料傳輸作業;其中,傳送端(Server)將優先權較高的資料插入前頭(Front-end),而優先權較低的資料則插入尾端(Back-end),此時接收端(Client)持續從資料前頭插入資料,以索取資料內容。
以上較為嚴謹、學術的相關概念,可能就要回到資料結構、演算法等相關學科了,不過作為一個使用者,我們仍可按著所見及所得(WYSIWYG)的觀點去認識並使用這些基本的容器。
以筆者自身私心的角度來看,比較常用的容器有(內建):
1.串列(list) 2.字典(dict) 3.元組(tuple)
其餘在 collection package 裡比較好用的有 :
1.雙頭隊列(deque) 2.命名元組(namedtuple)
@ 備註 : 上述的英文簡寫為顯示的(explicitly)物件定義介面
關於上述容器的API坊間已有許多文章介紹,故不在此贅述;實際上運用的場景:
# Basic API --
# Explicitly define --
int_lst = list([1, 2, 3])
# Implicitly define --
chr_lst = ['a', 'b', 'c']
mix_lst = []
mix_lst.append([ int_lst[:2] ]) # [ [[1, 2]] ] -> mixed list
mix_lst.append(chr_lst) # [ [[1, 2]], ['a', 'b', 'c']]
## Access the value in list with multi-dimension --
print(mix_lst[0][0][1]) # output : 2
print(mix_lst[1][1]) # output : 'b'
print(mix_lst[0][0]) # output : [1], not 1 !!
函數(function)的功能以實務的角度而言,像是將重複性高的程序(程式碼)包裝成 "一份" 程式碼片段,並在需要時呼叫它;這樣可以大幅減少重複的程式碼,並降低程式整體的複雜性。這個概念對於接觸過程式語言的人應該不陌生,而在 python 中定義函數也是一件簡單的事情;通常對於時常呼叫的函數,我們可以使用關鍵字 def 來產生 "函數物件" (函數也是前述所提到的物件),而對於程序內容"簡單"的函數,python 也提供了 lambda 關鍵字來產生匿名函數(anonymous function),使得函數可以像免洗碗筷--用完就丟的便利功能。
以下提供簡短程式碼範例,來計算並印出各個學生所有科目的平均分數:
# define function to show the result
def show_result(stud_dict):
print("name : {} \n.format(stdu_dict['name']))
print("avg score : {} \n".format(stdu_dict['score']))
if __name__ == "__main__":
stud_lst = ["John", "Marie", "Harry", "Kali", "Joseph"]
# score information
math_score = [50, 75, 66, 86, 12]
art_score = [40, 99, 78, 23, 63]
lang_score = [90, 70, 56, 88, 42]
scores_tup = [scores for scores in zip(math_score, art_score, lang_score)]
# lambda function with simple procedure
get_int_avg = lambda scores : int(sum(scores)/len(scores))
for (name, scores) in zip(stud_lst, scores_tup):
avg_score = get_int_avg(scores)
show_result({'name':name, 'score':avg_score})
類別(class) 像是一個模板(template),用於創建對應的物件(object),這些物件使的我們能將其對應到設計的系統,並藉由物件間的交流達成我們所想像的業務邏輯;如前所述,在 Python 中我們能自己定義類別,並創建許多物件來達成以上的需求。
在此舉一個具體的例子,若我們想要設計學生的成績管理系統;或許可以從使用者的角度設想,這個系統可能需要一個使用者的登入介面(User Interface)、一個接收與傳遞操作命令的管理者(daemon, 在系統中比較常用這個名子),以及一個背後的資料儲存庫(Data Storage)來紀錄分數。
從抽象的角度來看 Python 的類別,我們需要定義類別名(Class name)、類別屬性(Attribute)、類別方法(Method);其中,類別屬性就是位於該類別的變數,而類別方法則是位於該類別的函數,該函數可以操作與控制類別屬性,已使物件藉由與外界的互動能改變自身的狀態。為詳述一些細節,我們分別說明類別屬性和類別方法的定義:
class Person: ## Person is class name.
pass
person = Person()
## add the attribute via '.' dot operator
person.name = "Kali"
person.age = 15
person.weight = 64.5
## Finally, it's ugly and hard to maintain the class..
# person.py file
class Person:
def __init__(self, my_name, my_age, my_weight):
self.name = my_name
self.age = my_age
self.weight = my_weight
def print_info():
print("name : ", self.name)
print("age : ", self.age)
print("weight : ", self.weight)
Im_Kali = Person("Kali", 15, 64.5)
至此,相信讀者已對類別實現的語法有了初步的認識,而在眾多情況中物件間並非是完全獨立的,有時多個物件間有許多關聯(association);關於這種關聯,我們在這裡初淺列舉一下(畢竟這是一個廣大的議題)。物件間的關聯以其耦合程度(相依程度),由小至大可分為兩種:have-a 關係、is-a 關係;為便於舉例,設有兩個物件A, B,茲以下分述之。
# hava-a association
class A:
class B:
def __init__(_b):
self.attr_b = _b
def __init__(self, _b):
self.B_obj = B(_b)
有了上述的基礎知識後,我們可以初步運用到之前成績管理系統的例子中,而能寫出簡易的程式碼來定義所運用到的物件:
from some_gui_lib import basic_UI
import person
class Student(person.Person):
def __init__(self, my_name, my_age, my_weight,
stud_id, score_sheet):
self.name = name
self.age = age
self.weight = weight
self.stud_id = stud_id
self.score_sheet = score_sheet
super(person.Person).__init__(self)
def get_stud_id(self):
return self.stud_id
def get_stud_score(self):
return self.score_sheet
class stud_score_UI(win):
def __init__(self):
## initial inherited class via super keyword
super(stud_score_UI).__init__(self)
self.set_UI_compnt()
# you can omit this part
def set_UI_compnt(self):
#param = {...} ; layout_param = {...}
self.entry(**param).set_layout(**layout_param)
self.btn(**param).set_layout(**layout_param)
if __name__ == "__main__":
win = basic_UI.win()
win.main_loop()
在上述的例子中,我們的程式無法良好的運作(先撇開一些未實作的GUI和參數設定),原因是類別 "stud_score_UI" 提供的功能暫且只是原封不動地回傳初始化時的參數,也就是我們並未對資料作儲存與處理,中間也沒有守護程序(daemon)幫助我們做資料的交換與程序間的溝通;不過我們有機會在後面的例子中繼續還善這個程式(空殼)。
即使如此,上述程式仍非常簡要遞給出一個系統中 GUI 的雛形,他並未完成任何後端(backend)的工作,他只接收並回應使用者對他的請求,與此同時,使用者在使用整個軟體的過程中也只會跟這個GUI產生直接的互動,這樣的概念也多少實現了封裝(encapsulation)的思想,也就是說使用者依然 "可以看到" 一些類別中的重要屬性,。
廣義而言,雖然容器 "大多數" 都有提供儲存、刪除、更改物件的對應函數,但實現這些操作的方式卻仍有所區別,因為容器儲存資料的方式不盡相同;不過在遍歷容器內的各個物件上,python 卻提供了一種普遍的方式來讓我們存取容器中的物件。
如同前述所言,容器本身也是一種物件,有對應的許多
int_lst = list([1, 2, 3])
chr_lst = ['a', 'b', 'c']
# Counter-based for loop -- not recommand..
for idx in range(0, len(int_lst)): # len(.) -> length of obj
print(int_lst[idx])
# From Counter-based into range-based for loop
for item in chr_lst:
print(item)
## How about iterative togather in the for loop ?!
# Zip the items into iterator..
mix_iter= zip(int_lst, chr_lst)
# Added the index in the iteration..
for idx, (int_item, chr_item) in enumerate(mix_iterator):
print("The {}-st element ; int : {} ; chr : {}".format(
idx, int_item, chr_item))
Duck type 源起於一個語言哲學上的議題,如果一個未知的生物有翅膀、會游泳、會呱呱叫,在某種語言的脈絡下,將這種未知的生物稱為鴨子是否有其合理之處??
python 內的變數(variable)皆為物件(object),每個物件內都有相應的方法(method)可供使用,一般可以用函數 dir 查看物件內的方法,因此在進行運算時,許多運算子(operator)也會參照運算元的方法來決定計算的方式,例如:複寫 eq, add, div 等方法將改變物件之間的比較、相加、除法等行為;許多 python 的概念與細節也往往取決於該物件所擁有的方法是如何實踐的。
class my_cls:
def __init__(self, val):
self.val = val
def call():
print("my class is callable..")
def __add__(self, y):
print("we'll figure out x + y")
return self.val + y
def __eq__(self, y):
return (str(self.x) == y)
my_obj = my_cls(val=10)
## Now, you know when should you use the "..'..'." for present the string..
# when '...' in the string of "...".
print("The following output the method of 'my_obj' \n")
dir(my_obj)
var_y = 15
print("addition : {}".format(my_obj + var_y))
str_var_1 = "15" ; str_var_2 = "10"
print("Show strictly equal : {0} for {1}".format( \
(my_obj == str_var_1), str_var_1))
## format support {num} for format the order of output.
print("Show strictly equal : {1} for {0}".format( \
str_var_2, (my_obj == str_var_2)))
不過從 Duck Type 的觀念來看,運行 python 有時可能難以確定變數的 "型別",這容易造成一些程式架構設計上的難題;難以運用 "型別的概念來"
// 未完...2020/1/24